
#include "chessmind2.h"
#include "chesspane.h"
#include <algorithm>
#include <iterator>

using namespace std;

inline int min(int x, int y){
    return (x < y)? x:y;
}
inline int max(int x, int y){
    return (x > y)? x:y;
}

// 五子棋嘛！！当然是五个子了。。。。也可以实现为”八子棋“的
const int GridCount = 5;

float ChessMind2::how(Vector2& grid, const int N, const int m, const int n, int dx, int dy)
{
    int count = 1;
    float weight[2] = {0,0};
    if (N < 2 || N > GridCount) {    // 我们研究的是五子棋，只计算到 5格
        return 0;
    }
    
    int xMax = grid.size();
    int yMax = grid[0].size();
    int x, y;
    for(int i = 0; i < 2; i ++){                // 计算两个方向的棋子形势
        for(int j = 1; j < N; j++){             // 检查相邻 N个格子
            x = m + dx * j;                     // 计算目标棋子坐标
            y = n + dy * j;
            if (x < 0 || y < 0 || x >= xMax || y >= yMax)   // 越界，换方向
                break;
            else if (grid[x][y] == grid[m][n]){  // 同色，继续下一个格子
                count ++;
                continue;
            }
            else if (grid[x][y] != BLANKPLACE)           // 异色， 停止这个方向的查找
                break;
            // 空白格子。尝试填上一个棋子
            grid[x][y] = grid[m][n];
            weight[i] = how(grid, N+1, x, y, dx, dy);  // 递归计算
            grid[x][y] = BLANKPLACE;
            break;
        }
        dx = -dx;   // 更换反方向
        dy = -dy;
    }
    if (N < GridCount)
        return (weight[0] + weight[1])/2;
    if (count >= 2 * GridCount - 3)         // 双向可胜利
        return 2;
    else if (count >= GridCount - 1)    // 单向可胜利
        return 1;
    else
        return 0;
}

float ChessMind2::chance(Vector2& grid, const int& m, const int& n, const float* val)
{
    int direction[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};
    float value = 0;
    for (int d = 0; d < 4; d ++){               // 逐步查看四个方向的线上的情况
        for (int N = GridCount; N > 1; N --){   // 逐步查看是否已经有 N子同线了
            float weight = how(grid, N, m, n, direction[d][0], direction[d][1]);
            if (weight < 0.01)                  // 没有 N 子，看看有没有 N -1子
                continue;
            value += weight * val[N-2];         // 算上val[]中的权值参数
            break;
        }
    }
    return value;
}


float ChessMind2::AttackChance(Vector2& grid, const int& m, const int& n)
{
    float val[] = {0.3, 3, 40, 100};
    return chance(grid, m, n, val);
}


float ChessMind2::DefendChance(Vector2& grid, const int& m, const int& n)
{
    float val[] = {0.1, 1, 10, 80};
    return chance(grid, m, n, val);    
}


Map ChessMind2::BlackFilter(Vector2& grid)
{
    int xMax = grid.size();
    int yMax = grid[0].size();
    int sum = 0;
    // 计算棋子数目
    for(int x = 0; x < xMax; x ++){
        for (int y = 0; y < yMax; y ++)
            if (grid[x][y] == WHITECHESS || grid[x][y] == BLACKCHESS)
                sum ++;
    }
    // 遍历， 判断每个棋子周围是不是有足够的
    Map val;
    for(int x = 0; x < xMax; x ++)
        for (int y = 0; y < yMax; y ++){
            if (grid[x][y] != BLANKPLACE)
                continue;

            // 计算目标坐标范围
            int r = 2;
            if (sum < 10) r = 1;
            int mMin = max(0, x - r);
            int nMin = max(0, y - r);
            int mMax = min(xMax - 1, x + r);
            int nMax = min(yMax - 1, y + r);
            int count = 0;
            for(int m = mMin; m <= mMax; m ++)
                for (int n = nMin; n <= nMax; n ++)
                    if (grid[m][n] != BLANKPLACE)
                        count ++;
            // 有棋子，则有可能
            if (count>0)
                val.insert(Map::value_type(x, y));
        }
    return val;
}

